package com.coolw.test.sftp.spring;

import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 *  sftp 客户端,多线程使用
 * <p>
 * jsch的sftp(ChannelSftp、Session)是不能在多线程下进行公用的，如果需要在多线程下操作sftp,那么ChannelSftp、Session需要放在ThreadLocal中
 *
 * @author coolw
 * @date 2023/11/6 9:16
 */
@Slf4j
@Component
public class SftpMultiClient {

    private final ThreadLocal<ChannelSftp> channelThreadLocal = new ThreadLocal<>();
    private final ThreadLocal<Session> sessionThreadLocal = new ThreadLocal<>();

    @Autowired
    private SftpConfig config;

    public void connect() throws JSchException {
        JSch jsch = new JSch();

        // 新建会话
        Session session = jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
        session.setPassword(config.getPassword());
        // 跳过第一次连接时的确认提示
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect();

        // 获取通信通道
        Channel channel = session.openChannel("sftp");
        channel.connect();

        ChannelSftp channelSftp = (ChannelSftp) channel;

        sessionThreadLocal.set(session);
        channelThreadLocal.set(channelSftp);
        log.info("连接sftp服务器成功");
    }

    public Session getSession() throws JSchException {
        Session session = sessionThreadLocal.get();
        if (session == null || session.isConnected()) {
            connect();
        }
        return sessionThreadLocal.get();
    }

    public ChannelSftp getChannel() throws JSchException {
        ChannelSftp channelSftp = channelThreadLocal.get();
        if (channelSftp == null || channelSftp.isConnected()) {
            connect();
        }
        return channelThreadLocal.get();
    }

    public void disconnect() {
        ChannelSftp channelSftp = channelThreadLocal.get();
        if (channelSftp != null && !channelSftp.isConnected()) {
            channelSftp.disconnect();
        }

        Session session = sessionThreadLocal.get();
        if (session != null && !session.isConnected()) {
            session.disconnect();
        }

        channelThreadLocal.remove();
        sessionThreadLocal.remove();
    }
}
